package com.heo.server;

import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import com.heo.pub.ApplicationContextUtil;
import com.heo.pub.ServerConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;

public class NettyServerSlotBootstrap  extends Thread {
	
	private static Logger log = Logger.getLogger(NettyServerBootstrap.class);
	private int port = ServerConfig.SLOT_PORT;

	@Override
	public void run() {
		EventLoopGroup boss = new NioEventLoopGroup();// 创建处理连接的线程池:bossGroup，boss线程负责监听新的连接请求，当有新的连接进来时，将对应的channel指派一个worker线程来处理。
		EventLoopGroup worker = new NioEventLoopGroup();// 创建处理所有事件的线程池:workerGroup，Worker线程负责对该Channel的读写操作。
		try {
			// 指定需要执行的childHandler
			// 设置部分参数，如AdaptiveRecvByteBufAllocator缓存大小
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(boss, worker);// 传入上面开辟的线程池
			bootstrap.channel(NioServerSocketChannel.class);// 指定连接该服务器的channel类型
			bootstrap.option(ChannelOption.SO_BACKLOG, 128);
			bootstrap.option(ChannelOption.SO_TIMEOUT, 160);
			bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, ServerConfig.CONNECT_TIME_OUT);// 客户端连接超时，毫秒，netty超时
			bootstrap.childOption(ChannelOption.TCP_NODELAY, true);// 如果要求高实时性，有数据发送时就马上发送，就将该选项设置为true
			bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);// 是否启用心跳保活机制。在双方TCP套接字建立连接后（即都进入ESTABLISHED状态）并且在两个小时左右上层没有任何数据传输的情况下，这套机制才会被激活。
			bootstrap.childHandler(new ChannelInitializer<SocketChannel>()// 构建Handler处理流程
			{
				@Override
				protected void initChannel(SocketChannel socketChannel) throws Exception {
					ChannelPipeline p = socketChannel.pipeline();
					p.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
					p.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
					p.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
					p.addLast("ping", new IdleStateHandler(180, 0, 0, TimeUnit.SECONDS));
					p.addLast(ApplicationContextUtil.getApplicationContext().getBean(NettyServerSlotHandle.class));//用spring的情况下，获取handler的方式。在对应的handler道理定义该bean为多例
				}
			});
			// 阻塞等待服务器完全启动,线程同步阻塞等待服务器绑定到指定端口
			ChannelFuture f = bootstrap.bind(port).sync();
			if (f.isSuccess()) {
				log.info("NettyServerSlotBootstrap服务器启动成功。监听端口[" + port + "]");
			}
			// 成功绑定到端口之后,给channel增加一个管道关闭的监听器并同步阻塞,直到channel关闭,线程才会往下执行,结束进程。等待服务器退出
			f.channel().closeFuture().sync();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		} finally {
			// 优雅退出，释放线程池资源
			boss.shutdownGracefully();
			worker.shutdownGracefully();
			log.info("SocketServer服务器关闭。");
		}
	}
 
}
